#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using AbstractClass.NPerf.Framework;

namespace AbstractClass.NPerf
{
    /// <summary>
    /// Represents a type which loads a set of <see cref="TestFixture"/> from a test assembly.
    /// </summary>
    public class TestLoader
    {
        /// <summary>
        /// Loads a set of test fixtures from a test assembly.
        /// </summary>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <returns>A set of test fixture.</returns>
        public static IEnumerable<TestFixture> LoadAssembly(string assemblyPath)
        {
            Assembly assembly = Assembly.LoadFile(assemblyPath);
            return assembly.GetExportedTypes().Select(LoadType).Where(x => x != null);
        }

        /// <summary>
        /// Loads a test fixture from a type.
        /// </summary>
        /// <param name="testType">Type of the test.</param>
        /// <returns>A test fixture obtained from a type.</returns>
        public static TestFixture LoadType(Type testType)
        {
            if (testType.GetCustomAttributes(typeof (PerfTestFixtureAttribute), false).Length > 0)
            {
                var tf = new TestFixture();
                foreach (MethodInfo mi in testType.GetMethods())
                {
                    if (mi.IsConstructor || mi.IsAbstract || mi.GetParameters().Length > 0)
                        continue;
                    if (mi.GetCustomAttributes(typeof (PerfTestAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestFixtureSetUpAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestFixtureTearDownAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestIgnoreAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestSetUpAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestTearDownAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestCounterAttribute), false).Length > 0
                        || mi.GetCustomAttributes(typeof (PerfTestDescriptionAttribute), false).Length > 0)
                    {
                        foreach (object o in mi.GetCustomAttributes(false))
                        {
                            if (o is PerfTestFixtureSetUpAttribute)
                            {
                                tf.StartUpObjectMethod = mi;
                                tf.StartUpObjectType = testType;
                            }
                            if (o is PerfTestFixtureTearDownAttribute)
                            {
                                tf.TearDownObjectMethod = mi;
                                tf.TearDownObjectType = testType;
                            }
                            if (o is PerfTestSetUpAttribute)
                            {
                                tf.StartUpLocalObjectMethod = mi;
                                tf.StartUpLocalObjectType = testType;
                            }
                            if (o is PerfTestTearDownAttribute)
                            {
                                tf.TearDownLocalObjectMethod = mi;
                                tf.TearDownLocalObjectType = testType;
                            }
                            if (o is PerfTestAttribute)
                            {
                                var tu = new TestUnit(testType, mi) {IsIgnored = false, Fixture = tf};
                                tf.Units.Add(tu);
                                var attribute = o as PerfTestAttribute;
                                if (mi.GetCustomAttributes(typeof (PerfTestIgnoreAttribute), false).Length > 0)
                                {
                                    tu.IgnoredMessage =
                                        ((PerfTestIgnoreAttribute)
                                         mi.GetCustomAttributes(typeof (PerfTestIgnoreAttribute), false)[0]).Message;
                                    tu.IsIgnored = true;
                                }
                                if (mi.GetCustomAttributes(typeof (PerfTestDescriptionAttribute), false).Length > 0)
                                {
                                    tu.TestDescription = ((PerfTestDescriptionAttribute)
                                                          mi.GetCustomAttributes(typeof (PerfTestDescriptionAttribute),
                                                                                 false)[0]).TestDescription;
                                }
                                tu.TestTypes = attribute.TestTypes;
                                tu.TestIteration = attribute.TestIterations;
                                tu.Threads = attribute.Threads;
                            }
                            if (o is PerfTestCounterAttribute)
                            {
                                var tu = new TestUnit(testType, mi) {IsIgnored = false, Fixture = tf};
                                tf.Units.Add(tu);
                                var attribute = o as PerfTestCounterAttribute;
                                if (mi.GetCustomAttributes(typeof (PerfTestIgnoreAttribute), false).Length > 0)
                                {
                                    tu.IgnoredMessage =
                                        ((PerfTestIgnoreAttribute)
                                         mi.GetCustomAttributes(typeof (PerfTestIgnoreAttribute), false)[0]).Message;
                                    tu.IsIgnored = true;
                                }
                                if (mi.GetCustomAttributes(typeof (PerfTestDescriptionAttribute), false).Length > 0)
                                {
                                    tu.TestDescription = ((PerfTestDescriptionAttribute)
                                                          mi.GetCustomAttributes(typeof (PerfTestDescriptionAttribute),
                                                                                 false)[0]).TestDescription;
                                }

                                tu.TestTypes = new List<TestType> {TestType.None};
                                tu.IsGenericCounterUnit = true;
                                tu.CategoryName = attribute.CategoryName;
                                tu.CounterName = attribute.CategoryName;
                                tu.InstanceName = attribute.InstanceName;
                                tu.TestIteration = attribute.TestIterations;
                                tu.Threads = attribute.Threads;
                            }
                        }
                    }
                }
                return tf;
            }
            return null;
        }
    }
}